#pragma once

#include <iostream>
#include <pthread.h>
#include <queue>

namespace JKTP
{

template<class T,size_t N=5>
class ThreadPool
{
  private:
    std::queue<T> _bq;//任务队列
    size_t _n;//线程数
    pthread_mutex_t _mt;
    pthread_cond_t _ct;

    static ThreadPool<T,N>* _init;

  private:
    ThreadPool()
      :_n(N)
    {
      pthread_mutex_init(&_mt,nullptr);
      pthread_cond_init(&_ct,nullptr);
    }

    ThreadPool(const ThreadPool<T,N>&)=delete;
    ThreadPool<T,N>& operator=(const ThreadPool<T,N>&)=delete;

  private:
    void Lock()
    {
      pthread_mutex_lock(&_mt);
    }

    void Unlock()
    {
      pthread_mutex_unlock(&_mt);
    }

    void Wake()
    {
      pthread_cond_signal(&_ct);
    }

    void Wait()
    {
      pthread_cond_wait(&_ct,&_mt);
    }

    bool Empty()
    {
      return _bq.empty();
    }

    static void* Rountine(void* argc)
    {
      pthread_detach(pthread_self());
      ThreadPool<T,N>* pt=reinterpret_cast<ThreadPool<T,N>*>(argc);

      //线程取任务，执行任务
      while(true)
      {
        pt->Lock();
        while(pt->Empty())
        {
          pt->Wait();
        }

        T t;
        pt->Pop(&t);
        pt->Unlock();

        t();//执行任务的逻辑
      }
    }

    void Initializer()
    {
      pthread_t pt;
      for(int i=0;i!=_n;i++)
      {
        pthread_create(&pt,nullptr,Rountine,(void*)this);
      }
    }

  public:
    ~ThreadPool()
    {
      pthread_mutex_destroy(&_mt);
      pthread_cond_destroy(&_ct);
    }

    static ThreadPool<T,N>* GetInstance()
    {
      static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
      if(_init==nullptr)
      {
        pthread_mutex_lock(&lock);
        if(_init==nullptr)
        {
          _init=new ThreadPool<T,N>(); 
          _init->Initializer();
          std::cout<<"首次加载对象"<<std::endl;
        }
        pthread_mutex_unlock(&lock);
      }
      return _init;
    }

    void Push(const T& in)
    {
      Lock();
      _bq.push(in);
      Unlock();
      Wake();
    }

    void Pop(T* out)
    {
      T t=_bq.front();
      _bq.pop();
      *out=t;
    }
};
template<class T,size_t N>
ThreadPool<T,N>* ThreadPool<T,N>::_init=nullptr;

}
